package com.nengchuan.kbms.dfs.aspect;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.nengchuan.config.exception.NcException;
import com.nengchuan.kbms.dfs.annotation.UserOperateLogger;
import com.nengchuan.kbms.dfs.constant.BaseConstant;
import com.nengchuan.kbms.dfs.entity.dto.DataFolderDTO;
import com.nengchuan.kbms.dfs.entity.dto.DownloadFileDTO;
import com.nengchuan.kbms.dfs.entity.po.DataShareUser;
import com.nengchuan.kbms.dfs.entity.po.UserMessage;
import com.nengchuan.kbms.dfs.entity.po.UserOperateHistory;
import com.nengchuan.kbms.dfs.entity.vo.DataFileVO;
import com.nengchuan.kbms.dfs.service.DataFileInfoService;
import com.nengchuan.kbms.dfs.service.DataShareUserService;
import com.nengchuan.kbms.dfs.service.UserMessageService;
import com.nengchuan.kbms.dfs.service.UserOperateHistoryService;
import com.nengchuan.kbms.dfs.util.IpUtil;
import com.nengchuan.model.model.WrappedResult;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <b>Description:</b><br>
 * 用户操作历史切面（含消息提醒
 * @author Abe
 * @version 1.0
 * <br><b>Date:</b> 2020/4/1 10:32
 */
@Slf4j
//@Aspect
//@Component
public class UserOperateHistoryAspect {

    @Autowired
    private HttpServletRequest request;

    @Autowired
    private UserMessageService userMessageService;

    @Autowired
    private DataShareUserService dataShareUserService;

    @Autowired
    private UserOperateHistoryService userOperateHistoryService;

    @Autowired
    private DataFileInfoService dataFileInfoService;


    @Around("@annotation(com.nengchuan.kbms.dfs.annotation.UserOperateLogger) && @annotation(logger)")
    public Object around(ProceedingJoinPoint point, UserOperateLogger logger) throws Throwable {
        Object result = point.proceed();
        Long bizId = getBizId(point.getArgs(), result, logger);
        if (bizId == null) {
            return result;
        }
        // 插入操作记录
        insertUserOperateHistory(bizId, logger, BaseConstant.SUCCESS);
        if (UserOperateLogger.Type.SHARE == logger.type()) {
            // 分享消息
            sendShareMessage(bizId);
        }
        // 更新下载，预览次数
        dataFileInfoService.incrementCount(bizId, logger.type());
        return result;
    }

    @AfterThrowing(value = "@annotation(com.nengchuan.kbms.dfs.annotation.UserOperateLogger) && @annotation(logger)", throwing = "e")
    private void doAfterThrow(JoinPoint point, UserOperateLogger logger, Throwable e) {
        Long bizId = getBizId(point.getArgs(), null, logger);
        insertUserOperateHistory(bizId, logger, BaseConstant.FAIL);
        throw new NcException(e);
    }

    /**
     * 获取文件id
     * @param args 参数
     * @param logger UserOperateLogger 对象
     * @return
     */
    private Long getBizId(Object[] args, Object result, UserOperateLogger logger) {
        try {
            switch (logger.type()) {
                case DOWNLOAD:
                    if (args[0] instanceof DownloadFileDTO) {
                        DownloadFileDTO downloadFileDTO = (DownloadFileDTO) args[0];
                        return downloadFileDTO.getId();
                    }
                case PREVIEW:
                    return (Long) args[0];
                case CREATE:
                    return ((WrappedResult<DataFileVO>) result).getData().getId();
                case CREATE_FOLDER:
                case SHARE:
                    return ((WrappedResult<Long>) result).getData();
                case UPDATE_FOLDER:
                    return ((DataFolderDTO) args[0]).getId();
                default:
                    throw new NcException("暂不支持的类型");
            }
        } catch (Exception e) {
            if (e.getClass() != NullPointerException.class) {
                throw new NcException(e);
            }
        }
        return null;
    }

    /**
     * 插入记录，即使失败也不影响主业务流程
     */
    private void insertUserOperateHistory(Long fileId, UserOperateLogger logger, String optResult) {
        UserOperateHistory history = new UserOperateHistory();
        try {
            history.setBizId(fileId);
            history.setOptTypeCode(logger.type().value);
            history.setIp(IpUtil.getIp(request));
            history.setOptResult(optResult);
            userOperateHistoryService.save(history);
        } catch (Exception e) {
            log.error("插入记录失败: " + history, e);
        }
    }

    /**
     * 分享消息
     */
    private void sendShareMessage(Long shareId) {
        if (shareId == null) {
            log.warn("shareId 为空，无法插入分销消息");
            return;
        }
        try {
            QueryWrapper<DataShareUser> wrapper = new QueryWrapper<>();
            wrapper.lambda().eq(DataShareUser::getShareId, shareId);
            List<DataShareUser> userList = dataShareUserService.list(wrapper);
            List<UserMessage> messageList = userList.stream().map(user -> {
                UserMessage userMessage = new UserMessage();
                userMessage.setUserId(user.getReceiveUserId());
                userMessage.setMessageTypeCode(BaseConstant.MessageType.SHARE);
                userMessage.setBizId(shareId);
                userMessage.setTitle("文件分享提醒");
                userMessage.setContent("文件分享提醒");
                return userMessage;
            }).collect(Collectors.toList());
            userMessageService.saveBatch(messageList);
        } catch (Exception ex) {
            log.error("分享消息插入失败", ex);
        }
    }

}
